/*
 * Engine2d.cpp
 *
 *  Created on: 23-01-2012
 *      Author: Jarek
 */

#include "Engine2d.h"


#include <assert.h>
#include "ETexture.h"

#include "FreetypeWrapper/FontAtlas.h"
#include "FreetypeWrapper/FTBitmapFont.h"
#include "FreetypeWrapper/FTBitmapChar.h"

extern void         convertUTF8StringToWchar(wchar_t *dest, const char *src);
extern wchar_t      convertUTF8CharToWchar(const char *src, uint *bytes = NULL);
extern wchar_t      getNextWCharFromUTF8(char *(&src));
extern size_t       UTF8StringLength(const char *src);

bool 		Engine2d::cos = false;
AAsset* 	Engine2d::filePng = 0;


Engine2d::Engine2d() {
    fontAtlas           = NULL;
    utf8bufferSize      = 0;
    utf8buffer          = NULL;
    globalScale         = 1.0f;
    alignHeight         = 0.0f;
}

Engine2d::~Engine2d() {
	// TODO Auto-generated destructor stub
}

void Engine2d::setEngine2dSize(int w,int h) {
    screenWidth    	= w;
    screenHeight  	= h;
	minX			= 0;
	minY			= 0;
	maxX			= w;
	maxY			= h;

	screenWidth1	= w-1;
	screenHeight1	= h-1;
}

void Engine2d::clipImage(int *xClip, int *yClip, int *wClip, int *hClip){
	*wClip       += *xClip;
    *hClip       += *yClip;
    if(*xClip<minX)  *xClip   = minX;
    if(*yClip<minY)  *yClip   = minY;
    if(*xClip>maxX)  *xClip   = maxX;
    if(*yClip>maxY)  *yClip   = maxY;
    if(*wClip<minX)  *wClip   = minX;
    if(*hClip<minY)  *hClip   = minY;
    if(*wClip>maxX)  *wClip   = maxX;
    if(*hClip>maxY)  *hClip   = maxY;
    *wClip       -= *xClip;
    *hClip       -= *yClip;
}

void Engine2d::fillRect(int x1,int y1,int w,int h) {

	int xClip	= x1;
	int yClip	= y1;

	int wClip	= w;
	int hClip	= h;

//	clipImage(&xClip, &yClip, &wClip, &hClip);

	if(wClip<=0||hClip<=0)
		return;

	int xClip2 = xClip+wClip;
	int yClip2 = yClip+hClip;

	GLfloat		vertices[] = {
		xClip,	screenHeight-yClip2,
		xClip2,	screenHeight-yClip2,
		xClip,	screenHeight-yClip,
		xClip2,	screenHeight-yClip,
	};



	if(!cos) {
		LOGE("wspolrzedne prostokata--->1 %d %d", xClip, screenHeight-yClip2);
		LOGE("wspolrzedne prostokata--->2 %d %d", xClip2,screenHeight-yClip2);
		LOGE("wspolrzedne prostokata--->3 %d %d", xClip, screenHeight-yClip);
		LOGE("wspolrzedne prostokata--->4 %d %d", xClip2, screenHeight-yClip);
		cos = true;
	}
//	GLfloat		vertices[] = {
//		x1,	h,
//		w,	h,
//		x1,	y1,
//		x1,	y1,
//	};

	glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnable(GL_TEXTURE_2D);

}

void Engine2d::fillTriangle(int x1, int y1, int w, int h) {

	int xClip	= x1;
	int yClip	= y1;

	int wClip	= w;
	int hClip	= h;

	if(wClip<=0||hClip<=0)
		return;

	int xClip2 = xClip+wClip;
	int yClip2 = yClip+hClip;

//	GLfloat		vertices[] = {
//		xClip2,	screenHeight-yClip2,
//		xClip,	screenHeight-yClip,
//		xClip2,	screenHeight-yClip,
//	};

//	GLfloat		vertices[] = {
//		xClip,	screenHeight-yClip2,
//		xClip2,	screenHeight-yClip2,
//		(xClip + xClip2)/2,	screenHeight-yClip,
//	};

//	GLfloat		vertices[] = {
//		(xClip + xClip2)/2,	screenHeight-yClip, xClip,
//		xClip,	screenHeight-yClip2, xClip,
//		xClip2,	screenHeight-yClip2, xClip,
//	};
//
//	if(!cos) {
//		LOGE("wspolrzedne trojkata--->1 %d %d", (xClip + xClip2)/2, screenHeight-yClip);
//		LOGE("wspolrzedne trojkata--->2 %d %d", xClip, screenHeight-yClip2);
//		LOGE("wspolrzedne trojkata--->3 %d %d", xClip2,screenHeight-yClip2);
//		cos = true;
//	}
//
//	glDisable(GL_TEXTURE_2D);
//	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//	glVertexPointer(3, GL_FLOAT, 0, vertices);
//	glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
//	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//	glEnable(GL_TEXTURE_2D);

	//NEHE tutorial
	//------------------------------------------------------
	GLfloat vertices[] = {
			0.0f, 1.0f, 0.0f, 	//Top
			-1.0f, -1.0f, 0.0f, //Bottom Left
			1.0f, -1.0f, 0.0f 	//Bottom Right
	};

	glVertexPointer(3, GL_FLOAT, 0 , vertices);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
}

void Engine2d::fillPyramid(int x1, int y1, int z1, int w, int h) {
	int xClip	= x1;
	int yClip	= y1;
	int zClip 	= z1;

	int wClip	= w;
	int hClip	= h;

	if(wClip<=0||hClip<=0)
		return;

	int xClip2 = xClip+wClip;
	int yClip2 = yClip+hClip;
	int zClip2 = yClip+hClip;

	GLfloat		vertices[] = {
		(xClip + xClip2)/2,	screenHeight-yClip, (zClip + zClip2)/2,
		xClip,	screenHeight-yClip2, zClip,
		xClip2,	screenHeight-yClip2,
		(xClip + xClip2)/2,	screenHeight-yClip,

	};

	if(!cos) {
		LOGE("wspolrzedne trojkata--->1 %d %d", (xClip + xClip2)/2, screenHeight-yClip);
		LOGE("wspolrzedne trojkata--->2 %d %d", xClip, screenHeight-yClip2);
		LOGE("wspolrzedne trojkata--->3 %d %d", xClip2,screenHeight-yClip2);
		cos = true;
	}

	glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnable(GL_TEXTURE_2D);
}

/**
 * Draws current atlas on screen (texture with all letters).
 *
 */
void Engine2d::drawFreetypeAtlas(int x, int y)
{
	fontAtlas->renderAtlas(x, screenHeight - y);
    batcher.renderCurr();
}

/**
 * Draw text with graphic fonts.
 * @param font Font to use during drawing.
 * @param text Text to draw encoded in UTF8 (!).
 * @param x Horizontal text position.
 * @param y Vertical text position.
 * @param align Align definition.
 * @param scale Font image scale.
 * @param tracking Distance between characters.
 * @param angle Rotation angle in angles.
 */
void Engine2d::drawFont(FTBitmapFont *font, const char *text, int x, int y, int align, float scale, int tracking, float angle)
{
	if (font == NULL || text == NULL)
        return;

    drawFont(font, bufferedConvertUtf8ToWchar(text), x, y, align, scale, tracking, angle);
}

/**
 * Draw text with graphic fonts.
 * @param font Font to use during drawing.
 * @param text Text to draw.
 * @param x Horizontal text position.
 * @param y Vertical text position.
 * @param align Align definition.
 * @param scale Font image scale.
 * @param tracking Distance between characters.
 * @param angle Rotation angle in angles.
 */
void Engine2d::drawFont(FTBitmapFont *font, const wchar_t *text, int x, int y, int align, float scale, int tracking, float angle)
{
    assert(tracking == 0 && "TODO: tracking");

	if (font == NULL || text == NULL)
		return;

	glDisable(GL_CULL_FACE);

	// Count text length.
	int len = 0;
	for (len = 0; text[len] != 0; len++)
		;

	if (len == 0)
		return;

	// Horizontal align.
	if (align & ALIGN_FONT_RIGHT)
		x -= getTxtLen(font, text, scale, tracking);
	else if (align & ALIGN_FONT_CENTER)
		x -= getTxtLen(font, text, scale, tracking)/ 2.0f;

	// Vertical align.
	if (align & ALIGN_FONT_TOP)
		y += alignHeight * scale;
	else if (align & ALIGN_FONT_MIDDLE)
		y += (alignHeight * scale) / 2;

    glEnable(GL_SCISSOR_TEST);
    glScissor(minX, screenHeight - maxY, maxX - minX, maxY - minY);

    font->drawString(x, screenHeight - y, text, scale * globalScale);
    batcher.renderCurr();
    glScissor(0, 0, 0, 0);
    glDisable(GL_SCISSOR_TEST);
}

/**
 * Helper function for converting UTF8 to wchar with usage of built-in buffer.
 * When lenght of string is greater then buffer size, it reallocates a new buffer.
 * @param text Pointer to char array with UTF8 encoded string.
 * @return pointer to utf8buffer member.
 */
wchar_t *Engine2d::bufferedConvertUtf8ToWchar(const char *text)
{
    uint len = strlen(text) + 1;

    if (utf8bufferSize < len) {
        delete [] utf8buffer;
        utf8buffer      = new wchar_t[len]; // worst case scenario, all UTF8 symbols are encoded on one byte.
        utf8bufferSize  = len;
    }

    convertUTF8StringToWchar(utf8buffer, text);

    return utf8buffer;
}

int Engine2d::getFontHeight(FTBitmapFont *font)
{
    return font->getHeight();
}

int Engine2d::getTxtLen(FTBitmapFont *fonts, const char *text, float scale, int tracking)
{
    assert(tracking == 0 && "TODO: tracking");
    return fonts->getWidth(bufferedConvertUtf8ToWchar(text)) * scale * globalScale;
}

int Engine2d::getTxtLen(FTBitmapFont *fonts, const wchar_t *text, float scale, int tracking)
{
    assert(tracking == 0 && "TODO: tracking");
    return fonts->getWidth(text) * scale * globalScale;
}

/**
 * Font parse.
 * @param aStr Text to be parsed.
 * @param aTab Output table where parsed strings will be stored.
 * @param fontName Font name (for example "Arial").
 * @param fontSize Font size.
 * @return Output lines.
 **/
int Engine2d::fontParse(FTBitmapFont *fonts, char *aStr, char **aTab, int width, int tracking)
{
    uint currentLine = 0;
    char *lineStart = aStr;
    while (true) {
        wchar_t c = getNextWCharFromUTF8(aStr);
        bool splitNewLine = false;
        if (c == '\\' && convertUTF8CharToWchar(aStr) == 'n') {
            c = getNextWCharFromUTF8(aStr);
            splitNewLine = true;
        }
        if (c == '\n' || c == '\0' || splitNewLine) {
            uint lineLen = 0;
            char *tmp = lineStart;
            while (tmp != aStr) {
                ++tmp;
                ++lineLen;
            }
            if (splitNewLine) {
                --lineLen;
            }
            aTab[currentLine] = new char[lineLen];
            for (uint i = 0; i < lineLen - 1; ++i)
                aTab[currentLine][i] = *lineStart++;
            if (splitNewLine)
                lineStart += 2;
            else
                lineStart += 1;
            aTab[currentLine][lineLen - 1] = '\0';
            ++currentLine;
            if (c == '\0')
                break;
        }
    }

    return currentLine;
}


/**
 * Count lines for font parse.
 * @param aStr Text to be parsed.
 * @param width Render area width.
 * @return Output lines.
 **/
int Engine2d::fontParseLines(FTBitmapFont *fonts, char *aStr, int width, int tracking)
{
    uint linesCount = 1;
    char *lineStart = aStr;
    while (true) {
        wchar_t c = getNextWCharFromUTF8(aStr);
        if (c == '\0')
            break;
        if (c == '\n' || (c == '\\' && convertUTF8CharToWchar(aStr) == 'n'))
            ++linesCount;
    }

    return linesCount;
}
